package com.adcc.swingui.ui;

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

import java.awt.AlphaComposite;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.util.concurrent.TimeUnit;
import javax.swing.JComponent;
import org.jdesktop.core.animation.timing.Animator;
import org.jdesktop.core.animation.timing.TimingSource;
import org.jdesktop.core.animation.timing.TimingTargetAdapter;
import org.jdesktop.core.animation.timing.interpolators.SplineInterpolator;
import org.jdesktop.swing.animation.timing.sources.SwingTimerTimingSource;

/**
 *
 * @author illusion <anymorekvetch@gmail.com>
 */
public class YSwitchPanel extends JComponent {

    public static int FROM_LEFT = 10;
    public static int FROM_RIGHT = 20;
    public static int FROM_TOP = 30;
    public static int FROM_BUTTOM = 40;
    private Animator anim = null;
    private TimingSource ts = null;
    private JComponent currentComp = null;
    private JComponent orginComp = null;
    private BufferedImage orginCompImg = null;
    private BufferedImage currentCompImg = null;
    private double fraction = 0;
    private final int animQuitOffset = 100;
    private final int animEnterOffset = 30;
    private int currentDir = FROM_RIGHT;
    private ComponentSwitchEffect eft = null;

    public YSwitchPanel() {
        this(null);
        initTimingSource();
    }

    public YSwitchPanel(ComponentSwitchEffect eft) {
        setLayout(new YSwitchPanelLayout());
    }

    private void initTimingSource() {
        if (ts == null) {
            ts = new SwingTimerTimingSource();
            Animator.setDefaultTimingSource(ts);
            ts.init();
        }
    }

    @Override
    public void paint(Graphics g) {
        if (anim != null && anim.isRunning()) {
            if (orginCompImg == null && orginComp != null) {
                orginCompImg = createCompShot(orginComp);
            }
            if (currentCompImg == null && currentComp != null) {
                if (currentComp.getSize().width < 1 || currentComp.getSize().height < 1) {
                    currentComp.setSize(getWidth() - getInsets().left - getInsets().right, getHeight() - getInsets().bottom - getInsets().top);
                }
                currentCompImg = createCompShot(currentComp);
            }
            Graphics2D g2d = (Graphics2D) g;
            double frquit = fraction * 2;
            if (frquit >= 1) {
                frquit = 1d;
            }
            double frenter = (fraction - 0.7) / 0.3;
            if (frenter < 0) {
                frenter = 0;
            }
            AlphaComposite orgac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1 - (float) frquit);
            AlphaComposite curtac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) frenter);
            if (currentDir == FROM_LEFT) {

                g2d.setComposite(orgac);
                g2d.drawImage(orginCompImg, (int) (animQuitOffset * frquit), 0, this);
                g2d.setComposite(curtac);
                g2d.drawImage(currentCompImg, (int) (-animEnterOffset * (1 - frenter)), 0, this);
            } else if (currentDir == FROM_RIGHT) {
                g2d.setComposite(orgac);
                g2d.drawImage(orginCompImg, (int) (-animQuitOffset * frquit), 0, this);
                g2d.setComposite(curtac);
                g2d.drawImage(currentCompImg, (int) (animEnterOffset * (1 - frenter)), 0, this);
            } else if (currentDir == FROM_TOP) {
                g2d.setComposite(orgac);
                g2d.drawImage(orginCompImg, 0, (int) (animQuitOffset * frquit), this);
                g2d.setComposite(curtac);
                g2d.drawImage(currentCompImg, 0, (int) (-animEnterOffset * (1 - frenter)), this);
            } else {
                g2d.setComposite(orgac);
                g2d.drawImage(orginCompImg, 0, (int) (-animQuitOffset * frquit), this);
                g2d.setComposite(curtac);
                g2d.drawImage(currentCompImg, 0, (int) (animEnterOffset * (1 - frenter)), this);
            }

        } else {
            super.paint(g);
        }
    }

    public void switchTo(JComponent comp, int dir) {
        this.currentDir = dir;
        orginComp = currentComp;
        currentComp = comp;
        if (anim == null) {
            SplineInterpolator spline = new SplineInterpolator(1.00, 0.00, 0.00, 1.00);
            anim = new Animator.Builder(ts).setDuration(800, TimeUnit.MILLISECONDS).setInterpolator(spline).build();
            anim.addTarget(new TimingTargetAdapter() {
                @Override
                public void begin(Animator source) {
                    currentComp.setBounds(0, 0, getWidth(), getHeight());
                    removeAll();
                }

                @Override
                public void timingEvent(Animator source, double frac) {
                    fraction = frac;
                    repaint();
                }

                @Override
                public void end(Animator source) {
                    removeAll();
                    add(currentComp);
                    orginCompImg = null;
                    currentCompImg = null;
                    validate();
                    repaint();
                }
            });
        }
        if (anim.isRunning()) {
            anim.stop();
        }
        anim.restart();
    }

    class YSwitchPanelLayout implements LayoutManager {

        @Override
        public void addLayoutComponent(String name, Component comp) {
        }

        @Override
        public void removeLayoutComponent(Component comp) {
        }

        @Override
        public Dimension preferredLayoutSize(Container parent) {
            return parent.getSize();
        }

        @Override
        public Dimension minimumLayoutSize(Container parent) {
            return new Dimension(0, 0);
        }

        @Override
        public void layoutContainer(Container parent) {
            synchronized (parent.getTreeLock()) {
                if (anim != null && !anim.isRunning()) {
                    if (currentComp != null) {
                        Insets in = getInsets();
                        currentComp.setBounds(in.left, in.top, parent.getWidth() - in.left - in.right, parent.getHeight() - in.top - in.bottom);
                    }
                }
            }
        }
    }

    /**
     *  ******************** timing framework ***********************
     */
    /**
     * 创建组件缩略图
     *
     * @param component
     * @return
     */
    public BufferedImage createCompShot(JComponent component) {
        BufferedImage img = null;
        try {
            synchronized (component.getTreeLock()) {
                component.addNotify();
                component.validate();
            }
            img = createCompatibleTranslucentImage(component.getWidth(), component.getHeight());
            Graphics2D grap = img.createGraphics();
            component.print(grap);
            grap.dispose();
        } catch (Exception e) {
        }
        return img;
    }

    public BufferedImage createCompatibleTranslucentImage(int width,
            int height) {
        if (width < 1) {
            width = 1;
        }
        if (height < 1) {
            height = 1;
        }
        return GraphicsEnvironment.isHeadless() ? new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) : getGraphicsConfig().createCompatibleImage(width, height,
                Transparency.TRANSLUCENT);
    }

    private GraphicsConfiguration getGraphicsConfig() {
        return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
    }
}
